home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / telecom / 86 / pascal / nowwhat2.txt < prev    next >
Text File  |  1986-12-19  |  18KB  |  361 lines

  1.                                   Now What?
  2.                 OSS Personal Pascal and the beginner - part 2
  3.                             written by David Meile
  4.  
  5.      [Copyright 1986 David Meile, all rights reserved.  Permission is
  6.      given to Atari user groups to reprint this article, as long as
  7.      this statement is included.  OSS Personal Pascal is a product of
  8.      Optimized Systems Software, Inc.  I am not related to the company,
  9.      I simply bought their compiler.]
  10.  
  11.                          Windows, Graphics and Pascal
  12.      
  13.         One of the many nice things about OSS Personal Pascal is that it
  14.      provides the Pascal programmer with simple access to many of the GEM
  15.      operating system features.  Unfortunately, while access is simple,
  16.      it is not always EASY.  GEM requires a lot of prompting before it will
  17.      produce something like a Window.  But, once you get the basic idea
  18.      of how to access GEM from Pascal, it DOES become easier as you write
  19.      more programs.
  20.      
  21.         Last time, I said I was going to draw some lines.  Actually, I am
  22.      going to do a little more than that ... I am going to introduce the
  23.      basics of creating a Window to draw ON.  The program that follows is
  24.      called GRAPHICS.PAS.
  25.      
  26.                                  The program
  27.      
  28.      PROGRAM graphics;
  29.      
  30.      { Clear the screen and draw something }
  31.      
  32.        CONST
  33.          {$I gemconst.pas }
  34.      
  35.        TYPE
  36.          {$I gemtype.pas }
  37.      
  38.        VAR
  39.          x,y,w,h,
  40.          my_window   : integer;
  41.          my_event    : integer;
  42.          wind_type   : integer;
  43.          title       : Window_Title;
  44.      
  45.          { The following must be defined for completeness, but are not used }
  46.      
  47.          message     : Message_Buffer;
  48.          key         : integer;
  49.          bcnt,bstate : integer;
  50.          mx,my       : integer;
  51.          kbd_state   : integer;
  52.      
  53.        {$I gemsubs.pas }
  54.      
  55.      PROCEDURE Do_Graph;
  56.      
  57.      BEGIN
  58.        wind_type := G_Name;
  59.        title := ' Drawing a box ';
  60.        my_window := New_Window( wind_type, title, 0, 0, 0, 0 );
  61.        Hide_Mouse;
  62.        Open_Window( my_window, 0, 0, 0, 0 );
  63.        Set_Window( my_window );
  64.        Work_Rect( my_window, x, y, w, h );
  65.        Set_Clip( x, y, w, h );
  66.        Paint_Color( White );
  67.        Paint_Rect( 0, 0, w, h );
  68.        Line_Color( Black );
  69.        Text_Color( Black );
  70.        Draw_String( 10,10, 'You can draw text on screen too!');
  71.        Line( 15,15, 15,100 );
  72.        Line_To( 100,100 );
  73.        Line_To( 100,15 );
  74.        Line_To( 15,15 );
  75.        Line_To( 100,100 );
  76.        Line( 15,100, 100,15 );
  77.        Draw_String( 15,110, 'Click the left button to exit...');
  78.        my_event := Get_Event( E_Button, 1, 1, 1, 0,
  79.                               False, 0, 0, 0, 0,
  80.                               False, 0, 0, 0, 0,
  81.                               message, key, bcnt, bstate, mx, my, kbd_state );
  82.        Close_Window( my_window );
  83.        Show_Mouse;
  84.        Delete_Window( my_window );
  85.      END;
  86.      
  87.      BEGIN
  88.        IF Init_Gem >= 0 THEN
  89.          BEGIN
  90.            Do_Graph;
  91.            Exit_Gem;
  92.          END;
  93.      END.
  94.      
  95.                          And now ... the explanation
  96.      
  97.         Quite a lot of things are going on in that little program, right?
  98.      I am sure that you recognize most of the lines at the very end.  There
  99.      is the 'Init_Gem' function, asking GEM if it can create a new workspace.
  100.      There is the 'Exit_Gem' procedure, telling GEM that the program is
  101.      finished with the workspace.  And there is that funny line that simply
  102.      says 'Do_Graph'.
  103.      
  104.                         But first, a brief digression
  105.      
  106.         Pascal works best in small chunks of code, called PROCEDURES and
  107.      FUNCTIONS.  As you may remember, a function is a subprogram that, when
  108.      called, returns a single value.  The function 'Init_Gem' returns an
  109.      integer value greater or equal to zero when GEM can run the program.
  110.      
  111.         A PROCEDURE is a subprogram that, when called, performs some sort
  112.      of action.  It may (or may not) return one or more values.  Procedures
  113.      can require PARAMETERS, which are variables with some sort of value.
  114.      'Draw_String' is a procedure in the program above.  It's parameters
  115.      are two integer values and a string.  (Remember, strings are enclosed
  116.      by single quota marks - 'This is a string').  'Exit_Gem' is a procedure
  117.      with no parameters.
  118.      
  119.         One of the advantages of Pascal over BASIC is that procedures and
  120.      functions can have variables that do not affect the program outside
  121.      of that particular subprogram.  A short example:
  122.      
  123.      Program example1;
  124.      
  125.      VAR
  126.        a, b : integer;
  127.      
  128.        Procedure dark( x : integer; y : integer );
  129.      
  130.        VAR
  131.          a, b : integer;
  132.      
  133.        BEGIN {Procedure dark}
  134.          a := x;
  135.          b := a * y;
  136.          Writeln( 'a = ', a , ' b = ', b );
  137.        END; {dark}
  138.      
  139.      BEGIN {Main program example1}
  140.          a := 10;
  141.          b := 5;
  142.          dark( a, b );
  143.          Writeln( 'a = ', a, ' b = ', b );
  144.      END. {example 1}
  145.      
  146.         What do you think this short program will do?  Print out values
  147.      of 'a' and 'b' of course.  First, assign 10 to a and 5 to b.  Then
  148.      call the procedure dark.  The two parameters are a and b ... they are
  149.      called x and y WITHIN procedure dark.  Assign x to a (so a = 10) and
  150.      assign a * y to b (10 * 5 = 50, so b = 50).  The Writeln will print
  151.      out the following:
  152.      
  153.         a = 10 b = 50
  154.      
  155.         Now, exit dark and go back to the main program.  Here we print out
  156.      the values of a and b.  But the values of a and b have not changed
  157.      in the main program, they only changed within procedure dark.  So,
  158.      a is STILL 10 and b is STILL 5 in the main program.  The Writeln will
  159.      print out the following:
  160.      
  161.         a = 10 b = 5
  162.      
  163.         If you have followed this, congratulations!  You now know about LOCAL
  164.      (within a procedure) variables.
  165.      
  166.                         Now, back to the REAL program
  167.      
  168.         OK.  You can see that 'Do_Graph' is a procedure.  There are no
  169.      parameters, so any variables included in Do_Graph must be GLOBAL ..
  170.      that is, the variables listed at the top of the program apply to the
  171.      procedure as well.  A GLOBAL variable can be changed by ANY subprogram,
  172.      and should not be used much within your own programs.   'Proper' Pascal
  173.      programs almost always use LOCAL variables within procedures, passing
  174.      parameters back to the main program when necessary.
  175.      
  176.         With that in mind, let's look at what's going on in the procedure
  177.      called Do_Graph.  The first thing you can see are several assignments.
  178.      'wind_type' is an integer variable used in the function New_Window.
  179.      It can be made up of several parts, and describes the parts of the
  180.      GEM Window we want to be there.  These include the scroll bars, the
  181.      "close window" box, and the window name.  G_Name is an bit value
  182.      for the window name.  G_Close is another bit value for the close
  183.      window box.  When combined they produce an integer value that we can
  184.      assign to wind_type.  To include both, you would type:
  185.      
  186.         wind_type := G_Name | G_Close;
  187.      
  188.      Additional parts of a GEM window can be included:  G_Full, G_Move,
  189.      G_Info, etc.
  190.      
  191.         Since I'm going to have a window name, I may as well tell GEM what
  192.      it is, right?  That is the variable 'title'.  You'll notice that the
  193.      variable is declared 'title : Window_Title'.  Window_Title is a special
  194.      TYPE included in the GEMTYPE.PAS file.  If you're interested, you can
  195.      look at GEMTYPE.PAS to see how "special" types are declared.
  196.      
  197.         Having my two variables assigned, I make a call to the function
  198.      called 'New_Window'.  You can tell it is a function because it's on the
  199.      right side of an assignment statement.  The variable 'my_window' is
  200.      an integer, so the function New_Window returns an integer value.  The
  201.      function New_Window asks GEM to set up space for a window, and lets
  202.      Pascal know how to access it by number.  It also tells GEM what the
  203.      title for the window should be.
  204.      
  205.         I don't want the mouse arrow to clutter up my nice graphics screen,
  206.      so I tell GEM to hide it with the procedure 'Hide_Mouse'.  You MUST
  207.      include a 'Show_Mouse' somewhere in your program for every Hide_Mouse
  208.      you execute.  If you don't, when your program is finished, GEM will
  209.      still be hiding the mouse when you get back to the Desktop ... not
  210.      a pretty 'sight'!
  211.      
  212.         OK.  The mouse is in hiding, and I can safely OPEN a new window,
  213.      using the procedure 'Open_Window' (of course).  I tell GEM to open
  214.      the window it has reserved and to give me the maximum amount of space
  215.      to work with (the 0,0,0,0 tells GEM to make the window as BIG as possible,
  216.      which generally means full-screen.  Don't exceed the values that you used
  217.      in the New_Window function call...).  To make SURE that the window I
  218.      just opened is the one I will be using, I use the procedure 'Set_Window'.
  219.      If you have several windows open at once, you use Set_Window to tell
  220.      GEM which one you're going to be working with now.  Notice that the
  221.      variable 'my_window' lets GEM know WHICH window I'm talking about.
  222.  
  223.         The window is open and set.  I want to find out how much space I
  224.      have to work with, so I use the procedure 'Work_Rect'.  The variables
  225.      x,y,w, and h are given values by the procedure Work_Rect, and I can
  226.      use them in my program to determine several things.  The x and y tell
  227.      me where the 'origin' of the window is, and w and h tell me how wide
  228.      and high the window is.  This is useful information -- it means I don't
  229.      have to write separate procedures for each resolution mode (LOW, MEDIUM
  230.      and HIGH resolution).  Instead, I can restrict myself to the boundaries
  231.      given by these values.
  232.      
  233.         I can do better than that.  I can tell GEM to ignore things I draw
  234.      that are outside the window boundaries by making a call to 'Set_Clip'.
  235.      This procedure will take the values I got from Work_Rect and tell GEM
  236.      not to do any actual drawing outside of those boundaries.  Now, regardless
  237.      of how big or small my window is, I can draw on it without fear of
  238.      crashing the system by going outside of the window boundaries.
  239.      
  240.         I have my window on screen, but it's got the background color of
  241.      the GEM Desktop.  I much prefer to draw on a white background, so I
  242.      set the 'Paint_Color' to white and then tell GEM to paint the entire
  243.      window that color using 'Paint_Rect'.  Notice that the width and height
  244.      are passed to Paint_Rect.  I have set the origin at 0,0, which is the
  245.      upper left corner of the window (or it's supposed to be ... try it
  246.      using x,y instead of 0,0 and note the results).
  247.      
  248.         OK, I have a white background, so I'm going to draw things with
  249.      black lines.  I set 'Line_Color' and 'Text_Color' to black.  Then I
  250.      call procedure 'Draw_String'.  The two parameters are x and y pixel
  251.      values, x going horizontally and y going vertically.  10,10 is 10 pixels
  252.      to the right and 10 pixels down.
  253.      
  254.         Next, I draw some lines.  Ideally, I would be drawing a square,
  255.      with corners at 15,15 and 100,100.  However, it may not look like it
  256.      on your screen.  The reason for this is that there are MORE x pixels
  257.      than there are y pixels on your screen.  In LOW resolution there are
  258.      320 x 200 pixels.  In HIGH resolution there are 640 x 400 pixels. 
  259.      In MEDIUM resolution there are 640 x 200 pixels.  The first number
  260.      is the x pixel value, the second number is the y pixel value.
  261.      
  262.         For now, we'll not worry about it. BUT, if you're going to be doing
  263.      lots of graphics, you'll want to set up some sort of "fudge-factor" to
  264.      make things look right.  One possible solution is to multiply the x
  265.      value by some constant based on the resolution mode you are in.  For
  266.      example, in MEDIUM resolution, multiplying x by 3.2 would compensate.
  267.      (3.2 x 200 = 640.)
  268.      
  269.         There are two procedures for drawing lines: 'Line' and 'Line_To'.
  270.      The first requires two endpoints, the beginning of the line and the
  271.      end of the line.  The second requires one endpoint, using the end of
  272.      the last line as the beginning of the new line.
  273.      
  274.         My lines are drawn, and all of the text is also drawn.  The second
  275.      Draw_String is an absolute MUST.  The reason?  You should ALWAYS let
  276.      the person using your program know what to do next!  If the second
  277.      line were omitted, I would have no idea that I was supposed to press
  278.      the left mouse button to exit the program.  It is good programming
  279.      practice to include such 'hints' where they are needed.
  280.      
  281.         How do I tell when the left button is pressed?  I use the Pascal
  282.      function 'Get_Event'.  There are a LOT of parameters for this function.
  283.      Some are not needed just to test for a simple click on the left mouse
  284.      button.  These are duly noted in the VAR declaration part of the program.
  285.      'my_event' is an integer value returned by Get_Event.  In many cases,
  286.      your program would take this value and continue to do something else.
  287.      Here, it simply sets up the program to await a click of the 'ol mouse
  288.      button.
  289.      
  290.         Get_Event parameters needed to test the mouse button include
  291.      E_Button ("I'm waiting for a mouse button event..."), and several values
  292.      that follow.  The first '1' means "left mouse button", the second '1'
  293.      means "waiting for user to click button", the third '1' means "wait for
  294.      one click" and the '0' means "wait this long for the button click".  In
  295.      this case, that '0' is meaningless (as are the 'False' and other '0's in
  296.      the parameter list) since we are not using the E_Timer event flag.
  297.      Everything else is simply there for completeness.
  298.      
  299.         Once I click the mouse, I close the window I created with
  300.      'Close_Window'.  Then I 'Show_Mouse', because I hid it earlier and
  301.      I want to SEE the mouse arrow once my program is finished!  Then I
  302.      'Delete_Window', which releases the space GEM has allocated for my
  303.      window since I no longer need it.
  304.      
  305.         Done at last.  Look at all of that work, simply to draw a couple of
  306.      lines on the screen!  However, the next time I want to create a window
  307.      and draw some lines, it'll be that much easier...
  308.  
  309.                      Of RAM disks and Pascal programming
  310.  
  311.         If you have a 1040 ST, or a 520 ST with a 1 megabyte memory upgrade,
  312.      you can move the OSS Personal Pascal files from disk to a RAM disk.
  313.      This makes things like calling the compiler and linker MUCH faster.
  314.      You need to make sure that the RAM disk you are using can survive a
  315.      computer RESET.  Talk to your local Atari ST user group to see if they
  316.      have a copy of one of the many RAM disks available.  One such is called
  317.      ETERNAL.PRG,  another is available in an archive file called YARD.ARC.
  318.  
  319.         To automate moving your Pascal program files to the RAM disk, you 
  320.      need to look for a program such as FLDR2DSK.PRG, also available from many
  321.      bulletin boards and user groups.  I use this program, but do not put it
  322.      into the AUTO folder as the instructions mention.  The reason is that
  323.      my RAM disk is created on a number of disks, and there is no real reason
  324.      to reboot my system simply to load OSS Personal Pascal.
  325.  
  326.         If you own an Atari 520 ST without the memory upgrade, you can speed
  327.      things up somewhat by using a RAM disk and putting your programs on the
  328.      RAM disk instead of Pascal.  There are some instructions available to do
  329.      this, which should be available from your local user group.  If you can't
  330.      find them, I will be happy to copy them for the cost of a STAMPED self-
  331.      addressed envelope.  About the best you can hope for is a 200k RAM disk.
  332.  
  333.  
  334.                              Wrapping things up
  335.  
  336.         I'd like to thank everybody who sent me letters and E-Mail regarding
  337.      the first column.  In future months, you can expect to see some more
  338.      articles on working with OSS Personal Pascal.
  339.  
  340.         In next month's article, I will discuss reading from and saving to
  341.      files.  I'll also talk about using the pre-defined DIALOG boxes that
  342.      are accessible from OSS Personal Pascal.
  343.  
  344.         I'm open to answering some SIMPLE questions regarding
  345.      Personal Pascal. You can reach me via GEnie as D.MEILE, or
  346.      write (include a stamp, please) to:
  347.  
  348.                David Meile
  349.                Box 13038 - Dinkytown Station
  350.                Minneapolis, MN  55414
  351.  
  352.                            Additional reading
  353.  
  354.         If you are interested in a college text for Pascal, you might find
  355.      that AN INTRODUCTION TO PROGRAMMING AND PROBLEM SOLVING WITH PASCAL by
  356.      G. Michael Schneider, Steven W. Weingart and David M. Perlman is useful.
  357.         It is published by John Wiley and Sons, and the latest version was
  358.      published in (I believe) 1984.  It was the text used for beginning
  359.      programming classes at the University of Minnesota in Minneapolis when
  360.      I learned to program in Pascal.
  361.